/**
 * 
 */
package com.ekingstar.framework.security;

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.jasig.cas.client.util.CommonUtils;
import org.springframework.security.Authentication;
import org.springframework.security.AuthenticationException;
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
import org.springframework.security.ui.AbstractProcessingFilter;
import org.springframework.security.ui.cas.ServiceProperties;
import org.springframework.security.util.TextUtils;

import com.ekingstar.cas.client.CasFilterValidStatus;

/**
 * @author 
 * 
 */
public class LocalAndCasProcessingFilter extends AbstractProcessingFilter {	
	private ServiceProperties serviceProperties;
	private String loginUrl;
	public void setLoginUrl(String loginUrl) {
		this.loginUrl = loginUrl;
	}
		
	public  Authentication attemptAuthentication(HttpServletRequest request) throws AuthenticationException{
		return null;
	}
	/*
	 * (non-Javadoc)
	 * 
	 * @see org.springframework.security.ui.AbstractProcessingFilter#attemptAuthentication(javax.servlet.http.HttpServletRequest)
	 */
	// 统一身份认证
	public Authentication attemptCasAuthentication(
			final HttpServletRequest request) throws AuthenticationException {
		final String username = "_cas_stateful_";
		String password = request.getParameter("ticket");
		if (password == null) {
			password = "";
		}
		UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
				username, password);

		authRequest.setDetails(authenticationDetailsSource
				.buildDetails(request));

		return this.getAuthenticationManager().authenticate(authRequest);
	}

	// 本地认证
	public Authentication attemptLocalAuthentication(HttpServletRequest request)
			throws AuthenticationException {
		String username = obtainUsername(request);
		String password = obtainPassword(request);

		if (username == null) {
			username = "";
		}

		if (password == null) {
			password = "";
		}

		username = username.trim();

		UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
				username, password);

		// Place the last username attempted into HttpSession for views
		HttpSession session = request.getSession(false);

		if (session != null || getAllowSessionCreation()) {
			request.getSession().setAttribute("SPRING_SECURITY_LAST_USERNAME",
					TextUtils.escapeEntities(username));
		}

		// Allow subclasses to set the "details" property
		setDetails(request, authRequest);

		return this.getAuthenticationManager().authenticate(authRequest);
	}

	protected void setDetails(HttpServletRequest request,
			UsernamePasswordAuthenticationToken authRequest) {
		authRequest.setDetails(authenticationDetailsSource
				.buildDetails(request));
	}

	protected String obtainPassword(HttpServletRequest request) {
		return (String)request.getSession().getAttribute("j_password");
	}

	/**
	 * Enables subclasses to override the composition of the username, such as
	 * by including additional values and a separator.
	 * 
	 * @param request
	 *            so that request attributes can be retrieved
	 * 
	 * @return the username that will be presented in the
	 *         <code>Authentication</code> request token to the
	 *         <code>AuthenticationManager</code>
	 */
	protected String obtainUsername(HttpServletRequest request) {
		return (String)request.getSession().getAttribute("j_username");
	}

	public void doFilterHttp(HttpServletRequest request,
			HttpServletResponse response, FilterChain chain)
			throws IOException, ServletException {

		if (requiresAuthentication(request, response)) {
			if (logger.isDebugEnabled()) {
				logger.debug("Request is to process authentication");
			}

			Authentication authResult;

			try {
				onPreAuthentication(request, response);
				
				String step = (String)request.getSession().getAttribute("step");

				if (step != null && "precheck".equals(step.trim())){
					try{
					 authResult = attemptCasAuthentication(request);
					}catch(AuthenticationException casFailed){
						//
						request.getSession().setAttribute("step",null);
						response.sendRedirect(request.getContextPath()+"/index.jsp?displayError=no");
						return;
					}
				}
				else if (step != null && "local".equals(step.trim())){
					//先验证ticket,如果失败则本地认证
					try{
					authResult = attemptCasAuthentication(request);
					}catch(AuthenticationException casFailed){
						authResult = attemptLocalAuthentication(request);
					}
				}else{
					//保存用户名和密码然后跳到统一身份认证验证 
					String username = request.getParameter("j_username");
					String password = request.getParameter("j_password");
					request.getSession().setAttribute("j_username", username);
					request.getSession().setAttribute("j_password", password);
					request.getSession().setAttribute("step", "local");
					
					//判断认证服务器是否开启
				    boolean isvalid = CasFilterValidStatus.isValidEndPoint(this.loginUrl);
				    if(isvalid){
				    	String urlEncodedService = CommonUtils.constructServiceUrl(null, response,this.serviceProperties.getService(), null, "ticket",true);
						String casAddress = this.loginUrl+"?isLoginService=true&username="+username+"&password="+password+"&service="+urlEncodedService;
					    response.sendRedirect(casAddress);
						return;
				    }else{
				    	//先验证ticket(统一身份认证),如果失败则本地认证
						try{
							authResult = attemptCasAuthentication(request);
						}catch(AuthenticationException casFailed){
							authResult = attemptLocalAuthentication(request);
						}
				    }
				}

			} catch (AuthenticationException failed) {
				// Authentication failed
				request.getSession().setAttribute("step",null);
				unsuccessfulAuthentication(request, response, failed);

				return;
			}

			// Authentication success
			/*
			 * if (continueChainBeforeSuccessfulAuthentication) {
			 * chain.doFilter(request, response); }
			 */
			request.getSession().setAttribute("step", null);
			successfulAuthentication(request, response, authResult);

			return;
		}

		chain.doFilter(request, response);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.springframework.security.ui.AbstractProcessingFilter#getDefaultFilterProcessesUrl()
	 */
	@Override
	public String getDefaultFilterProcessesUrl() {
		// TODO Auto-generated method stub
		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.springframework.core.Ordered#getOrder()
	 */
	public int getOrder() {
		// TODO Auto-generated method stub
		return 0;
	}
	public void setServiceProperties(ServiceProperties serviceProperties) {
		this.serviceProperties = serviceProperties;
	}

}
